package com.kstudio.videocapture.editvideo;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;

import com.kstudio.videocapture.editvideo.KVideoEditPlayer.KVideoEditPlayerListener;
import com.kstudio.videocapture.editvideo.KVideoEditViewSeekBar.KSeekViewListener;
import com.kstudio.videocapture.util.KLog;

public class KVideoEditControl extends ViewGroup implements OnClickListener, KSeekViewListener, KVideoEditPlayerListener {
    private final KLog log = new KLog("KVideoEdit");

    private static final int LAYOUT_UPDATE_NONE     = 0x0000;
    private static final int LAYOUT_UPDATE_VIDEO    = 0x0001;
    private static final int LAYOUT_UPDATE_CONTROL  = 0x0002;

    private Context mContext;
    private KEditControlLayout  mLayout = new KEditControlLayout();
    private int                 mChangedLayout;
    private boolean             isEnabled;

    private KVideoEditPlayer         mPlayer;
    private KVideoEditViewSeekBar    mSeekBar;
    private KVideoEditPlayPauseView  mBtnPlayPause;
    private Button                   mBtnSaveFrameSingle;
    private Button                   mBtnSaveFrameMulti;
    private KVideoEditImageBoxView   mRepositoryView;
    private ProgressBar              mProgress;

    private KEditControlListener mListener;

    private class KEditControlLayout {
        int LAYOUT_TOP_PADDING = 0;
        int LAYOUT_LEFT_PADDING = 0;
        int LAYOUT_RIGHT_PADDING = 0;
        int BTN_GAP_PADDING = 0;

        int BTN_SAVEFRAME_SINGLE_WIDTH = 0;
        int BTN_SAVEFRAME_SINGLE_HEIGHT = 0;

        int BTN_SAVEFRAME_MULTI_WIDTH = 0;
        int BTN_SAVEFRAME_MULTI_HEIGHT = 0;

        int BTN_REPOSITORY_WIDTH = 0;
        int BTN_REPOSITORY_HEIGHT = 0;

        int    SHOW_DELAY = 10;
        long   SHOW_ROOP_TIME = 0;
        double SHOW_SEEKBAR_BOTTOM_POS = 0;
        double SHOW_BTN_LEFT_POS = 0;
        float  SHOW_ALPHA = 1f;
    }

    public interface KEditControlListener {
        void onSingleSaveButtonClick(int time);
        void onMultiSaveButtonClick(int time);
        void onRepositoryButtonClick();
    }

    public KVideoEditControl(Context context) {
        this(context, null);
    }

    public KVideoEditControl(Context context, AttributeSet attrs) {
        this(context, attrs , 0);
    }

    public KVideoEditControl(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mContext = context;
        mListener = null;

        mState = STATE_SHOW;
        mChangedLayout = LAYOUT_UPDATE_NONE;
        isEnabled = false;

        this.setOnClickListener(this);

        createLayout();
        setAttribute(attrs,defStyle);
    }

    public void setOnEditControlListener(KEditControlListener l) {
        mListener = l;
    }

    public void setDuration(int duration) {
        mSeekBar.setDuration(duration);
    }

    public void setVideoPath(String filepath) {
        mPlayer.KSetVideoPath(filepath);
    }

    public void setRepositoryImage(Bitmap bm) {
        mRepositoryView.setMode(KVideoEditImageBoxView.MODE_IMAGE);
        mRepositoryView.setImage(bm);
    }

    public void setGroupEnabled(boolean enable) {
        if(isEnabled == enable)
            return;

        isEnabled = enable;
        if(isEnabled) mProgress.setVisibility(View.GONE);
        else          mProgress.setVisibility(View.VISIBLE);

        mBtnSaveFrameSingle.setEnabled(isEnabled);
        mBtnSaveFrameMulti.setEnabled(isEnabled);
        mRepositoryView.setEnabled(isEnabled);
        mBtnPlayPause.setEnabled(isEnabled);
    }

    public boolean getGroupEnabled() { return isEnabled; }

    public Rect getEffectDstRect() {
        return mRepositoryView.getRectImage();
    }



    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if(mPlayer != null) {
            mPlayer.measure(widthMeasureSpec, heightMeasureSpec);
        }
        if(mSeekBar != null) {
            mSeekBar.measure(widthMeasureSpec, heightMeasureSpec);
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if(changed) mChangedLayout = LAYOUT_UPDATE_VIDEO | LAYOUT_UPDATE_CONTROL;

        if(mChangedLayout != LAYOUT_UPDATE_NONE) {
            int left = l;
            int top = t;
            int right = 0;
            int bottom = 0;

            if((mChangedLayout & LAYOUT_UPDATE_VIDEO) == LAYOUT_UPDATE_VIDEO) {
                left = (r - l - mPlayer.getMeasuredWidth()) / 2;
                top = (b - t - mPlayer.getMeasuredHeight()) / 2;
                right = left + mPlayer.getMeasuredWidth();
                bottom = top + mPlayer.getMeasuredHeight();
                mPlayer.layout(left, top, right, bottom);
                mChangedLayout ^= LAYOUT_UPDATE_VIDEO;
            }

            if((mChangedLayout & LAYOUT_UPDATE_CONTROL) == LAYOUT_UPDATE_CONTROL) {
                left = mLayout.LAYOUT_LEFT_PADDING;
                top = mLayout.LAYOUT_TOP_PADDING;
                right = left + mLayout.BTN_SAVEFRAME_SINGLE_WIDTH - (int)mLayout.SHOW_BTN_LEFT_POS;
                bottom = top + mLayout.BTN_SAVEFRAME_SINGLE_HEIGHT;
                mBtnSaveFrameSingle.layout(left, top, right, bottom);

                top = bottom + mLayout.BTN_GAP_PADDING;
                right = left + mLayout.BTN_SAVEFRAME_MULTI_WIDTH - (int)mLayout.SHOW_BTN_LEFT_POS;
                bottom = top + mLayout.BTN_SAVEFRAME_MULTI_HEIGHT;
                mBtnSaveFrameMulti.layout(left, top, right, bottom);

                right = left + mRepositoryView.geWidthBox()  - (int)mLayout.SHOW_BTN_LEFT_POS;
                top = bottom + mLayout.BTN_GAP_PADDING;
                bottom = top + mRepositoryView.getHeightBox();
                mRepositoryView.layout(left, top, right, bottom);

                right = left + mRepositoryView.geWidthBox()  - (int)mLayout.SHOW_BTN_LEFT_POS;
                top = bottom + mLayout.BTN_GAP_PADDING;
                bottom = top + mRepositoryView.getHeightBox();
                mProgress.layout(left, top, right, bottom);

                left = (r - l - mBtnPlayPause.getDrawableWidth()) / 2;
                top = (b - t - mBtnPlayPause.getDrawableHeight()) / 2;
                right = left + mBtnPlayPause.getDrawableWidth();
                bottom = top + mBtnPlayPause.getDrawableHeight();
                mBtnPlayPause.layout(left, top, right, bottom);

                left = l;
                top = b - t - mSeekBar.getMeasuredHeight() + (int)mLayout.SHOW_SEEKBAR_BOTTOM_POS;
                right = left + mSeekBar.getMeasuredWidth();
                bottom = b + (int)mLayout.SHOW_SEEKBAR_BOTTOM_POS;
                mSeekBar.layout(left, top, right, bottom);

                mChangedLayout ^= LAYOUT_UPDATE_CONTROL;
            }
        }
    }

    @Override
    public void onClick(View v) {
        if(isEnabled == false)  return;

        if(this == v) {
            log.i("KVideoEditControl : onClick - this");
            showhideControl();
        } else if(mBtnSaveFrameSingle == v ) {
            log.i("KVideoEditControl : onClick - Save Frame Single");
            singleSaveClick();
        } else if(mBtnSaveFrameMulti == v ) {
            log.i("KVideoEditControl : onClick - Multi Frame Single");
            multiSaveClick();
        } else if(mRepositoryView == v ) {
            log.i("KVideoEditControl : onClick - Repository");
            repositoryClick();
        } else if(mBtnPlayPause == v) {
            switch(mBtnPlayPause.getState()) {
                case KVideoEditPlayPauseView.PLAY :
                    if(mPlayer.KPlay()) {
                        log.i("KVideoEditControl : onClick - Play");
                        mBtnPlayPause.setState(KVideoEditPlayPauseView.PAUSE);
                    }
                    break;
                case KVideoEditPlayPauseView.PAUSE :
                    if(mPlayer.KPause()) {
                        log.i("KVideoEditControl : onClick - Pause");
                        mBtnPlayPause.setState(KVideoEditPlayPauseView.PLAY);
                    }
                    break;
            }
        }
    }

    @Override
    public void onKSeekViewChangeTime(int time) {
        mPlayer.KSeekTo(time);
    }

    @Override
    public void onKVideoEditPlayerPrepared() {
        setGroupEnabled(true);
        mChangedLayout |= LAYOUT_UPDATE_VIDEO;
    }

    @Override
    public void onKVideoEditPlayerError() {
        // TODO Auto-generated method stub

    }

    @Override
    public void onKVideoEditPlayerCompletion() {
        mSeekBar.setThumbCompletion();
        mBtnPlayPause.setState(KVideoEditPlayPauseView.PLAY);
    }

    @Override
    public void onKVideoEditPlayerSeekBarSetDuration(int duration) {
        mSeekBar.setDuration(duration);
    }

    @Override
    public int onKVideoEditPlayerSeekBarGetWidth() {
        return mSeekBar.getSeekBarWidth();
    }

    @Override
    public void onKVideoEditPlayerSeekBarUpdate(int time) {
        mSeekBar.setThumbTime(time);
    }


    private void setAttribute(AttributeSet attrs, int defStyle) {
        int[] ids = new int[attrs.getAttributeCount()];
        for (int i = 0; i < attrs.getAttributeCount(); i++) {
            ids[i] = attrs.getAttributeNameResource(i);
        }

        TypedArray a = mContext.obtainStyledAttributes(attrs, ids, defStyle, 0);

        for (int i = 0; i < attrs.getAttributeCount(); i++) {
            String attrName = attrs.getAttributeName(i);
            if (attrName == null)
                continue;

            if (attrName.equals("layout_top_padding")) {
                mLayout.LAYOUT_TOP_PADDING = a.getDimensionPixelSize(i, 0);
            } else if (attrName.equals("layout_left_padding")) {
                mLayout.LAYOUT_LEFT_PADDING = a.getDimensionPixelSize(i, 0);
            } else if (attrName.equals("layout_right_padding")) {
                mLayout.LAYOUT_RIGHT_PADDING = a.getDimensionPixelSize(i, 0);
            } else if (attrName.equals("btn_gap_padding")) {
                mLayout.BTN_GAP_PADDING = a.getDimensionPixelSize(i, 0);
            } else if (attrName.equals("btn_saveframe_single_drawable")) {
                Drawable d = a.getDrawable(i);
                Drawable e = d.getCurrent();
                mLayout.BTN_SAVEFRAME_SINGLE_WIDTH = ((BitmapDrawable)(e)).getBitmap().getWidth();
                mLayout.BTN_SAVEFRAME_SINGLE_HEIGHT = ((BitmapDrawable)(e)).getBitmap().getHeight();

                mBtnSaveFrameSingle.setBackground(d);
            } else if (attrName.equals("btn_saveframe_multi_drawable")) {
                Drawable d = a.getDrawable(i);
                Drawable e = d.getCurrent();
                mLayout.BTN_SAVEFRAME_MULTI_WIDTH = ((BitmapDrawable)(e)).getBitmap().getWidth();
                mLayout.BTN_SAVEFRAME_MULTI_HEIGHT = ((BitmapDrawable)(e)).getBitmap().getHeight();

                mBtnSaveFrameMulti.setBackground(d);
            } else if (attrName.equals("btn_repository_drawable")) {
                Drawable d = a.getDrawable(i);

                mRepositoryView.setBaseDrawable(d);
            } else if (attrName.equals("btn_empty_box_drawable")) {
                Drawable d = a.getDrawable(i);

                mRepositoryView.setBoxDrawable(d);
            } else if (attrName.equals("seekbar_size_text")) {
                int size = a.getDimensionPixelSize(i, 0);
                mSeekBar.setTextSize(size);
            } else if (attrName.equals("seekbar_padding_left")) {
                mSeekBar.setPaddingLeft(a.getDimensionPixelSize(i,0));
            } else if (attrName.equals("seekbar_padding_right")) {
                mSeekBar.setPaddingRight(a.getDimensionPixelSize(i,0));
            } else if (attrName.equals("seekbar_padding_top")) {
                mSeekBar.setPaddingTop(a.getDimensionPixelSize(i,0));
            } else if (attrName.equals("seekbar_padding_bottom")) {
                mSeekBar.setPaddingBottom(a.getDimensionPixelSize(i,0));
            } else if (attrName.equals("seekbar_padding_text")) {
                mSeekBar.setPaddingText(a.getDimensionPixelSize(i,0));
            } else if (attrName.equals("seekbar_bm_left")) {
                Bitmap b = BitmapFactory.decodeResource(a.getResources(), a.getResourceId(i, 0));
                mSeekBar.setBmLeft(b);
            } else if (attrName.equals("seekBar_bm_right")) {
                Bitmap b = BitmapFactory.decodeResource(a.getResources(), a.getResourceId(i, 0));
                mSeekBar.setBmRight(b);
            } else if (attrName.equals("seekBar_bm_center")) {
                Bitmap b = BitmapFactory.decodeResource(a.getResources(), a.getResourceId(i, 0));
                mSeekBar.setBmCenter(b);
            } else if (attrName.equals("seekBar_bm_centerpassed")) {
                Bitmap b = BitmapFactory.decodeResource(a.getResources(), a.getResourceId(i, 0));
                mSeekBar.setBmCenterPassed(b);
            } else if (attrName.equals("seekbar_bm_edgeleft")) {
                Bitmap b = BitmapFactory.decodeResource(a.getResources(), a.getResourceId(i, 0));
                mSeekBar.setBmEdgeLeft(b);
            } else if (attrName.equals("seekBar_bm_edgeright")) {
                Bitmap b = BitmapFactory.decodeResource(a.getResources(), a.getResourceId(i, 0));
                mSeekBar.setBmEdgeRight(b);
            } else if (attrName.equals("seekBar_bm_thumb")) {
                Bitmap b = BitmapFactory.decodeResource(a.getResources(), a.getResourceId(i, 0));
                mSeekBar.setBmThumb(b);
            }
        }

        a.recycle();
    }

    private void createLayout() {
        mPlayer = new KVideoEditPlayer(mContext);
        mPlayer.KSetVideoPlayerListener(this);
        addView(mPlayer);

        mBtnSaveFrameSingle = new Button(mContext);
        mBtnSaveFrameSingle.setOnClickListener(this);
        mBtnSaveFrameSingle.setEnabled(false);
        addView(mBtnSaveFrameSingle);

        mBtnSaveFrameMulti = new Button(mContext);
        mBtnSaveFrameMulti.setOnClickListener(this);
        mBtnSaveFrameMulti.setEnabled(false);
        addView(mBtnSaveFrameMulti);

        mRepositoryView = new KVideoEditImageBoxView(mContext);
        mRepositoryView.setOnClickListener(this);
        addView(mRepositoryView);

        mProgress = new ProgressBar(mContext);
        mProgress.setVisibility(View.GONE);
        addView(mProgress);

        mBtnPlayPause = new KVideoEditPlayPauseView(mContext);
        mBtnPlayPause.setEnabled(false);
        mBtnPlayPause.setOnClickListener(this);
        addView(mBtnPlayPause);

        mSeekBar = new KVideoEditViewSeekBar(mContext);
        mSeekBar.setSeekViewListener(this);
        addView(mSeekBar);
    }

    private void singleSaveClick() {
        if(mListener != null) {
            mListener.onSingleSaveButtonClick(mSeekBar.getThumbTime());
        } else {
            log.w("singleSaveClick : mListener is null");
        }
    }

    private void multiSaveClick() {
        if(mListener != null) {
            mListener.onMultiSaveButtonClick(mSeekBar.getThumbTime());
        } else {
            log.w("singleSaveClick : mListener is null");
        }
    }

    private void repositoryClick() {
        if(mListener != null) {
            mListener.onRepositoryButtonClick();
        } else {
            log.w("repositoryClick : mListener is null");
        }
    }

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case HANDLER_SHOW_CONTROL:
                    if(mState == STATE_SHOWING) {
                        long loopTime = System.currentTimeMillis();
                        long delay = loopTime - mLayout.SHOW_ROOP_TIME;
                        mLayout.SHOW_ROOP_TIME = loopTime;

                        mLayout.SHOW_SEEKBAR_BOTTOM_POS -= (double)mSeekBar.getMeasuredHeight() * (double)delay / (double)SHOW_DURARION;
                        mLayout.SHOW_BTN_LEFT_POS       -= (double)(mLayout.LAYOUT_LEFT_PADDING + mLayout.BTN_SAVEFRAME_SINGLE_WIDTH) * (double)delay / (double)SHOW_DURARION;
                        mLayout.SHOW_ALPHA              += (float)((double)delay / (double)SHOW_DURARION);

                        if(mLayout.SHOW_SEEKBAR_BOTTOM_POS < 0 || mLayout.SHOW_BTN_LEFT_POS < 0 || mLayout.SHOW_ALPHA > 1) {
                            mLayout.SHOW_SEEKBAR_BOTTOM_POS = 0;
                            mLayout.SHOW_BTN_LEFT_POS = 0;
                            mLayout.SHOW_ALPHA = 1f;

                            mHandler.sendEmptyMessageDelayed(HANDLER_SHOW_CONTROL_DONE, mLayout.SHOW_DELAY);
                        } else {
                            mHandler.sendEmptyMessageDelayed(HANDLER_SHOW_CONTROL, mLayout.SHOW_DELAY);
                        }

                        setAlphaControl(mLayout.SHOW_ALPHA);
                        mChangedLayout |= LAYOUT_UPDATE_CONTROL;
                        requestLayout();
                    }
                    break;

                case HANDLER_SHOW_CONTROL_DONE :
                    if(mState == STATE_SHOWING) {
                        mState = STATE_SHOW;
                    }
                    break;

                case HANDLER_HIDE_CONTROL:
                    if(mState == STATE_HIDING) {
                        long loopTime = System.currentTimeMillis();
                        double delay = loopTime - mLayout.SHOW_ROOP_TIME;
                        mLayout.SHOW_ROOP_TIME = loopTime;

                        mLayout.SHOW_SEEKBAR_BOTTOM_POS += (double)mSeekBar.getMeasuredHeight() * (double)delay / (double)SHOW_DURARION;
                        mLayout.SHOW_BTN_LEFT_POS       += (double)(mLayout.LAYOUT_LEFT_PADDING + mLayout.BTN_SAVEFRAME_SINGLE_WIDTH) * (double)delay / (double)SHOW_DURARION;
                        mLayout.SHOW_ALPHA              -= (float)((double)delay / (double)SHOW_DURARION);

                        if(mLayout.SHOW_SEEKBAR_BOTTOM_POS > mSeekBar.getMeasuredHeight() ||
                           mLayout.SHOW_BTN_LEFT_POS       > (mLayout.LAYOUT_LEFT_PADDING + mLayout.BTN_SAVEFRAME_SINGLE_WIDTH) ||
                           mLayout.SHOW_ALPHA              < 0 ) {
                            mLayout.SHOW_SEEKBAR_BOTTOM_POS = mSeekBar.getMeasuredHeight();
                            mLayout.SHOW_BTN_LEFT_POS = mLayout.LAYOUT_LEFT_PADDING + mLayout.BTN_SAVEFRAME_SINGLE_WIDTH;
                            mLayout.SHOW_ALPHA = 0f;

                            mHandler.sendEmptyMessageDelayed(HANDLER_HIDE_CONTROL_DONE, mLayout.SHOW_DELAY);
                        } else {
                            mHandler.sendEmptyMessageDelayed(HANDLER_HIDE_CONTROL, mLayout.SHOW_DELAY);
                        }

                        setAlphaControl(mLayout.SHOW_ALPHA);
                        mChangedLayout |= LAYOUT_UPDATE_CONTROL;
                        requestLayout();
                    }
                    break;


                case HANDLER_HIDE_CONTROL_DONE :
                    if(mState == STATE_HIDING) {
                        mState = STATE_HIDE;
                    }
                    break;

                default:
                    break;
            }
        }
    };

    private static final int STATE_SHOWING  = 0x0002;
    private static final int STATE_SHOW     = 0x0003;
    private static final int STATE_HIDING   = 0x0004;
    private static final int STATE_HIDE     = 0x0005;

    private static final int HANDLER_SHOW_CONTROL        = 0x0001;
    private static final int HANDLER_SHOW_CONTROL_DONE   = 0x0002;
    private static final int HANDLER_HIDE_CONTROL        = 0x0003;
    private static final int HANDLER_HIDE_CONTROL_DONE   = 0x0004;

    private int mState;
    private static final int SHOW_DURARION = 300;

    private void showhideControl() {
        if(mState == STATE_HIDE || mState == STATE_HIDING) {
            mState = STATE_SHOWING;
            mLayout.SHOW_ROOP_TIME = System.currentTimeMillis();
            mHandler.removeMessages(HANDLER_SHOW_CONTROL);
            mHandler.sendEmptyMessageDelayed(HANDLER_SHOW_CONTROL, mLayout.SHOW_DELAY);
        } else if(mState == STATE_SHOW || mState == STATE_SHOWING) {
            mState = STATE_HIDING;
            mLayout.SHOW_ROOP_TIME = System.currentTimeMillis();
            mHandler.removeMessages(HANDLER_HIDE_CONTROL);
            mHandler.sendEmptyMessageDelayed(HANDLER_HIDE_CONTROL, mLayout.SHOW_DELAY);
        }
    }

    private void setAlphaControl(float alpha) {
        mBtnSaveFrameMulti.setAlpha(alpha);
        mBtnSaveFrameSingle.setAlpha(alpha);
        mRepositoryView.setAlpha(alpha);
        mBtnPlayPause.setAlpha(alpha);
    }
}
